package spring.boot.btc.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import spring.boot.btc.common.BlockProperty;
import spring.boot.btc.model.*;

import java.util.ArrayList;
import java.util.List;

@Slf4j
@Service
public class BlockMsgHandlerService {

    @Autowired
    private BlockService blockService;

    @Autowired
    private BlockSenderService blockSenderService;

    @Autowired
    private BlockVerifyService blockVerifyService;

    public void doHandlerMsg(String msg) {
        JSONObject json = JSON.parseObject(msg);
        int type = json.getIntValue("type");
        log.info("接收广播  type=[{}]", type);
        if (1 == type) {
            log.info("接收挖矿广播1、开始处理挖矿广播消息");
            Block block = json.getObject("msg", Block.class);
            miningMsgHandler(block);
        } else if (2 == type) {
            JSONObject transJson = json.getJSONObject("msg");
            sendMoneyMsgHandler(transJson);
        } else if (3 == type) {
            log.info("接收转账收款人区块信息1、开始获取区块，添加到自己的链中");
            Block block = json.getObject("msg", Block.class);
            receiveMoneyMsgHandler(block);
        }
    }


    private void miningMsgHandler(Block block) {
        TransactionInput input = block.getTransaction().getTransactionInputList().get(0);
        if (input.getType() == 1) {
            log.info("接收挖矿广播2、系统挖矿");
            TransactionOutput output = block.getTransaction().getTransactionOutputList().get(0);
            if (output.getAddress().equals(Wallet.getInstance().getAddress())) {
                log.info("接收挖矿广播3、本机系统挖矿，不操作");
            } else {
                log.info("接收挖矿广播3、非本机系统挖矿，开始添加到区块链中");
                String preHash = block.getPreHash();
                long version = block.getVersion();
                if (preHash.equals(BlockProperty.getLast().getHash()) && (version - BlockProperty.getLast().getVersion()) == 1) {
                    if (blockVerifyService.testBlock(block)) {
                        blockService.addToLast(block, 2);
                        log.info("接收挖矿广播4、非本机系统挖矿，添加到区块链中，验证签名成功，添加成功");
                    } else {
                        log.info("接收挖矿广播4、非本机系统挖矿，添加到区块链中，验证区块签名失败，不添加");
                    }
                } else {
                    log.info("接收挖矿广播4、非本机系统挖矿，添加到区块链中，未指向上一个区块，不添加");
                }
            }
        } else {
            log.info("接收挖矿广播2、系统挖矿系统错误，请检查区块数据type");
        }
    }


    private void sendMoneyMsgHandler(JSONObject transJson) {
        JSONArray inputs = transJson.getJSONArray("inputs");
        TransactionInput input = JSON.parseObject(JSON.toJSONString(inputs.get(0)), TransactionInput.class);
        if (input.getAddress().equals(Wallet.getInstance().getAddress())) {
            log.info("接收转账人转账信息1、自己的转账，直接忽略");
            return;
        }
        String address = transJson.getString("address");
        if (Wallet.getInstance().getAddress().equals(address)) {
            log.info("接收转账人转账信息1、自己是转账收款人，开始收款");
            List<TransactionInput> inputList = new ArrayList<>();
            for (int i = 0; i < inputs.size(); i++) {
                TransactionInput tranInput = JSON.parseObject(JSON.toJSONString(inputs.get(i)), TransactionInput.class);
                inputList.add(tranInput);
            }

            List<TransactionOutput> outputList = new ArrayList<>();
            long money = transJson.getLongValue("money");
            TransactionOutput output = new TransactionOutput(Wallet.getInstance().getPublicKeyString(), money);
            outputList.add(output);

            JSONArray outputs = transJson.getJSONArray("outputs");
            if (outputs != null && outputs.size() > 0) {
                for (int i = 0; i < outputs.size(); i++) {
                    TransactionOutput tranOutput = JSON.parseObject(JSON.toJSONString(outputs.get(i)), TransactionOutput.class);
                    outputList.add(tranOutput);
                }
            }
            Transaction transaction = new Transaction(inputList, outputList);
            Block lastBlock = BlockProperty.getLast();

            //定义初始工作量
            long nonce = 1L;
            long now = System.currentTimeMillis();
            while (true) {
                Block block = new Block(lastBlock.getHash(), lastBlock.getVersion() + 1, nonce, transaction, now);
                String hash = block.getHash();
                if (hash.startsWith("0000")) {
                    log.info("本次转账工作量计算成功，计算次数为:[{}],hash:[{}......]", nonce, hash.substring(0, 20));
                    blockService.addToLast(block, 2);
                    JSONObject blockJson = new JSONObject();
                    blockJson.put("type", 3);
                    blockJson.put("msg", block);
                    blockSenderService.send(blockJson.toJSONString());
                    log.info("接收转账人转账信息2、自己是转账收款人，组合转账区块完毕，广播区块到其他节点");
                    break;
                }
                nonce++;
            }
        } else {
            log.info("接收转账人转账信息1、自己不是转账人和收款人，直接忽略消息");
        }
    }


    private void receiveMoneyMsgHandler(Block block) {
        if (blockVerifyService.testBlock(block)) {
            log.info("接收转账收款人区块信息2、验证区块成功，开始获取区块，添加到自己的链中");
            blockService.addToLast(block, 2);
        } else {
            log.info("接收转账收款人区块信息2、验证区块失败");
        }
    }

}
